

from CvPythonExtensions import *
import CvUtil
import CvMapGeneratorUtil
import random
import sys
from math import sqrt
from CvMapGeneratorUtil import FractalWorld
from CvMapGeneratorUtil import TerrainGenerator
from CvMapGeneratorUtil import FeatureGenerator


def getDescription():
	return "Generates a map with moon terrain"

def getNumCustomMapOptions():
	return 8
	
def getCustomMapOptionName(argsList):
	[iOption] = argsList
	option_names = {
		0:	"Terrain Features",
		1:	"TXT_KEY_MAP_SCRIPT_MOUNTAIN_PATTERN",
		2:	"TXT_KEY_MAP_SCRIPT_MOUNTAIN_DENSITY",
		3:	"Rille Density",
		4:	"Terrae Density",
		5:	"Dust Sea Setting",
		6:	"Crater Rim Density",
		7:	"Maria Setting"
		}
	translated_text = unicode(CyTranslator().getText(option_names[iOption], ()))
	return translated_text

def getNumCustomMapOptionValues(argsList):
	[iOption] = argsList
	option_values = {
		0:	1,
		1:	3,
		2:	3,
		3:  3,
		4:  3,
		5:  4,
		6:  3,
		7:  2
		}
	return option_values[iOption]

def getCustomMapOptionDescAt(argsList):
	[iOption, iSelection] = argsList
	selection_names = {
		0:	{
			0: "Rilles/cratered/domes"
			},
		1:	{
			0: "TXT_KEY_MAP_SCRIPT_SCATTERED",
			1: "TXT_KEY_MAP_SCRIPT_RIDGELINES",
			2: "TXT_KEY_MAP_SCRIPT_CLUSTERED"
			},
		2:	{
			0: "TXT_KEY_MAP_SCRIPT_DENSE_PEAKS",
			1: "TXT_KEY_MAP_SCRIPT_NORMAL_PEAKS",
			2: "TXT_KEY_MAP_SCRIPT_THIN_PEAKS"
			},
		3:	{
			0: "Low",
			1: "Medium",
			2: "High"
			},
		4:	{
			0: "Low",
			1: "Medium",
			2: "High"
			},
		5:  {
			0: "Off",
			1: "Small",
			2: "Medium",
			3: "Large"
			},
		6:	{
			0: "Low",
			1: "Medium",
			2: "High"
			},
		7:	{
			0: "Scattered",
			1: "Clustered on one side of moon"
			}
		}
	translated_text = unicode(CyTranslator().getText(selection_names[iOption][iSelection], ()))
	return translated_text
	
def getCustomMapOptionDefault(argsList):
	[iOption] = argsList
	option_defaults = {
		0:	0,
		1:	1,
		2:	2,
		3:  1,
		4:  0,
		5:  0,
		6:  1,
		7:  1
		}
	return option_defaults[iOption]

def isAdvancedMap():
	"This map should show up in simple mode"
	return 0
	
def isClimateMap():
	return 0

def isSeaLevelMap():
	return 0

def getWrapX():
	return True
def getWrapY():
	return False


def getGridSize(argsList):
	"Reduce grid sizes by one level."
	grid_sizes = {
		WorldSizeTypes.WORLDSIZE_DUEL:		(8,5),
		WorldSizeTypes.WORLDSIZE_TINY:		(10,6),
		WorldSizeTypes.WORLDSIZE_SMALL:		(13,8),
		WorldSizeTypes.WORLDSIZE_STANDARD:	(16,10),
		WorldSizeTypes.WORLDSIZE_LARGE:		(21,13),
		WorldSizeTypes.WORLDSIZE_HUGE:		(26,16)
	}

	if (argsList[0] == -1): # (-1,) is passed to function on loads
		return []
	[eWorldSize] = argsList
	return grid_sizes[eWorldSize]

def minStartingDistanceModifier():
	return -35
	
def generatePlotTypes():
	gc = CyGlobalContext()
	map = CyMap()
	dice = gc.getGame().getMapRand()
	iFlags = 0  # Disallow FRAC_POLAR flag, to prevent "zero row" problems.
	iW = map.getGridWidth()
	iH = map.getGridHeight()
	plotTypes = [PlotTypes.PLOT_LAND] * (iW*iH)
	terrainFrac = CyFractal()

	
	# Get custom map user inputs.
	userInputGrain = map.getCustomMapOption(1)
	userInputPeaks = map.getCustomMapOption(2)
	userInputHills = map.getCustomMapOption(3)

	
	
	# Varying grains for hills/peaks per map size and Mountain Ranges setting.
	# [clustered_grain, ridgelines_grain, scattered_grain]
	worldsizes = {
		WorldSizeTypes.WORLDSIZE_DUEL:      [3,4,5],
		WorldSizeTypes.WORLDSIZE_TINY:      [3,4,5],
		WorldSizeTypes.WORLDSIZE_SMALL:     [4,5,6],
		WorldSizeTypes.WORLDSIZE_STANDARD:  [4,5,6],
		WorldSizeTypes.WORLDSIZE_LARGE:     [4,5,6],
		WorldSizeTypes.WORLDSIZE_HUGE:      [4,5,6]
		}
	grain_list = worldsizes[map.getWorldSize()]
	grain_list.reverse()
	grain = grain_list[userInputGrain]
	
	# Peak density
	peak_list = [80, 87, 93]
	hill_list = [50, 55, 60]
	#peak_list = [70, 77, 83]
	#hill_list = [40, 45, 50]
	peaks = peak_list[userInputPeaks]
	hills = hill_list[userInputHills]
	
	terrainFrac.fracInit(iW, iH, grain, dice, 0, -1, -1)

	iHillsThreshold = terrainFrac.getHeightFromPercent(hills)
	iPeaksThreshold = terrainFrac.getHeightFromPercent(peaks)

	# Now the main loop, which will assign the plot types.
	for x in range(iW):
		for y in range(iH):
			i = y*iW + x
			val = terrainFrac.getHeight(x,y)
			if val >= iPeaksThreshold:
				plotTypes[i] = PlotTypes.PLOT_PEAK
			elif val >= iHillsThreshold and val < iPeaksThreshold:
				plotTypes[i] = PlotTypes.PLOT_HILLS
			else:
				plotTypes[i] = PlotTypes.PLOT_LAND
	return plotTypes
	
class MoonTerrainGenerator(CvMapGeneratorUtil.TerrainGenerator):
	def __init__(self, fracXExp=-1, fracYExp=-1, grain_amount=3,
                     iMariaBasaltPercent=50,
                     iCrateredPercent=50):

		self.gc = CyGlobalContext()
		self.map = CyMap()

		self.grain_amount = grain_amount
		
		self.gc = CyGlobalContext()
		self.map = CyMap()

		self.iWidth = self.map.getGridWidth()
		self.iHeight = self.map.getGridHeight()

		self.mapRand = self.gc.getGame().getMapRand()
		self.iFlags = 0

		self.userInputMaria = self.map.getCustomMapOption(7)
		if self.userInputMaria == 1:
			self.MariaMaxLongitude = self.iWidth / 2
		else:
			self.MariaMaxLongitude = self.iWidth

		self.MariaBasalt=CyFractal()
		self.Cratered=CyFractal()
		self.variation=CyFractal()

		self.iMariaBasaltTopPercent = 100
		self.iMariaBasaltBottomPercent = max(0,int(100-iMariaBasaltPercent))
		self.iCrateredTopPercent = 100
		self.iCrateredBottomPercent = max(0,int(100-iCrateredPercent))

		self.iMariaBasaltPercent = iMariaBasaltPercent
		self.iCrateredPercent = iCrateredPercent

		self.fracXExp = fracXExp
		self.fracYExp = fracYExp

		self.initFractals()
		
	def initFractals(self):
		self.MariaBasalt.fracInit(self.iWidth, self.iHeight, self.grain_amount+1, self.mapRand, self.iFlags, self.fracXExp, self.fracYExp)
		self.iMariaBasaltTop = self.MariaBasalt.getHeightFromPercent(self.iMariaBasaltTopPercent)
		self.iMariaBasaltBottom = self.MariaBasalt.getHeightFromPercent(self.iMariaBasaltBottomPercent)

		self.Cratered.fracInit(self.iWidth, self.iHeight, self.grain_amount+1, self.mapRand, self.iFlags, self.fracXExp, self.fracYExp)
		self.iCrateredTop = self.Cratered.getHeightFromPercent(self.iCrateredTopPercent)
		self.iCrateredBottom = self.Cratered.getHeightFromPercent(self.iCrateredBottomPercent)

		self.variation.fracInit(self.iWidth, self.iHeight, self.grain_amount, self.mapRand, self.iFlags, self.fracXExp, self.fracYExp)

		self.terrainMariaBasalt = self.gc.getInfoTypeForString("TERRAIN_MARIABASALT")
		self.terrainCratered = self.gc.getInfoTypeForString("TERRAIN_CRATERED")

	def generateTerrain(self):		
		terrainData = [0]*(self.iWidth*self.iHeight)
		for x in range(self.iWidth):
			for y in range(self.iHeight):
				iI = y*self.iWidth + x
				terrain = self.generateTerrainAtPlot(x, y)
				terrainData[iI] = terrain

		return terrainData

	def generateTerrainAtPlot(self,iX,iY):
		terrainVal = self.MariaBasalt
		if iX < self.MariaMaxLongitude:
			mariabasaltVal = self.MariaBasalt.getHeight(iX, iY)
			if ((mariabasaltVal >= self.iMariaBasaltBottom) and (mariabasaltVal <= self.iMariaBasaltTop)):
				terrainVal = self.terrainMariaBasalt
			else:
				terrainVal = self.terrainCratered
		else:
			terrainVal = self.terrainCratered

		if (terrainVal == TerrainTypes.NO_TERRAIN):
			return self.map.plot(iX, iY).getTerrainType()
		return terrainVal

def generateTerrainTypes():
	NiTextOut("Generating Terrain (Python Moon Map) ...")
	
	terraingen = MoonTerrainGenerator()
	terrainTypes = terraingen.generateTerrain()

	return terrainTypes
	
def add_Polar():
	iPolarBottomLatitude=0.88
	iPolarTopLatitude=0.12
	gc = CyGlobalContext()
	dice = gc.getGame().getMapRand()
	map = gc.getMap()
	iW = map.getGridWidth()
	iH = map.getGridHeight()
	Polar = gc.getInfoTypeForString("TERRAIN_POLAR")
	Terrae = gc.getInfoTypeForString("TERRAIN_TERRAE")
	Polar_coords = [0] * (15*2)
	for x in range(iW):
		for y in range(iH):
			lat = y/float(iH)
			if ((lat > iPolarBottomLatitude) or (lat < iPolarTopLatitude)):
				Polar_size = 0
				Polar_size_ok = True
				Corner1_Checked=False
				Corner2_Checked=False
				Corner3_Checked=False
				Corner4_Checked=False
				Plot = map.plot(x,y)
				if Plot.isFlatlands() or Plot.isWater():
					Polar_size += 1
					Polar_coords[(Polar_size * 2) - 2]=x
					Polar_coords[(Polar_size * 2) - 1]=y
					#--------------------------------------------------------------------------------------------------------------------------------------------------
					xx = x
					yy = y+1
					Plot = map.plot(xx,yy)
					if Plot.isFlatlands() or Plot.isWater():
						Polar_size += 1
						Polar_coords[(Polar_size * 2) - 2]=xx
						Polar_coords[(Polar_size * 2) - 1]=yy
						xx = x
						yy = y+2
						Plot = map.plot(xx,yy)
						if Plot.isFlatlands() or Plot.isWater():
							Polar_size_ok = False
						else:
							xx = x-1
							yy = y+1
							Corner1_Checked=True
							Plot = map.plot(xx,yy)
							if Plot.isFlatlands() or Plot.isWater():
								Polar_size += 1
								Polar_coords[(Polar_size * 2) - 2]=xx
								Polar_coords[(Polar_size * 2) - 1]=yy
								xx = x-2
								yy = y+1
								Plot = map.plot(xx,yy)
								if Plot.isFlatlands() or Plot.isWater():
									Polar_size_ok = False
								else:
									xx = x-1
									yy = y+2
									Plot = map.plot(xx,yy)
									if Plot.isFlatlands() or Plot.isWater():
										Polar_size_ok = False
							xx = x+1
							yy = y+1
							Corner2_Checked=True
							Plot = map.plot(xx,yy)
							if Plot.isFlatlands() or Plot.isWater():
								Polar_size += 1
								Polar_coords[(Polar_size * 2) - 2]=xx
								Polar_coords[(Polar_size * 2) - 1]=yy
								xx = x+1
								yy = y+2
								Plot = map.plot(xx,yy)
								if Plot.isFlatlands() or Plot.isWater():
									Polar_size_ok = False
								else:
									xx = x+2
									yy = y+1
									Plot = map.plot(xx,yy)
									if Plot.isFlatlands() or Plot.isWater():
										Polar_size_ok = False
					#--------------------------------------------------------------------------------------------------------------------------------------------------
					if Polar_size_ok:
						xx = x+1
						yy = y
						Plot = map.plot(xx,yy)
						if Plot.isFlatlands() or Plot.isWater():
							Polar_size += 1
							Polar_coords[(Polar_size * 2) - 2]=xx
							Polar_coords[(Polar_size * 2) - 1]=yy
							xx = x+2
							yy = y
							Plot = map.plot(xx,yy)
							if Plot.isFlatlands() or Plot.isWater():
								Polar_size_ok = False
							else:
								xx = x+1
								yy = y-1
								Corner3_Checked=True
								Plot = map.plot(xx,yy)
								if Plot.isFlatlands() or Plot.isWater():
									Polar_size += 1
									Polar_coords[(Polar_size * 2) - 2]=xx
									Polar_coords[(Polar_size * 2) - 1]=yy
									xx = x+2
									yy = y-1
									Plot = map.plot(xx,yy)
									if Plot.isFlatlands() or Plot.isWater():
										Polar_size_ok = False
									else:
										xx = x+1
										yy = y-2
										Plot = map.plot(xx,yy)
										if Plot.isFlatlands() or Plot.isWater():
											Polar_size_ok = False
								if not Corner2_Checked:		
									xx = x+1
									yy = y+1
									Plot = map.plot(xx,yy)
									if Plot.isFlatlands() or Plot.isWater():
										Polar_size += 1
										Polar_coords[(Polar_size * 2) - 2]=xx
										Polar_coords[(Polar_size * 2) - 1]=yy
										xx = x+1
										yy = y+2
										Plot = map.plot(xx,yy)
										if Plot.isFlatlands() or Plot.isWater():
											Polar_size_ok = False
										else:
											xx = x+2
											yy = y+1
											Plot = map.plot(xx,yy)
											if Plot.isFlatlands() or Plot.isWater():
												Polar_size_ok = False
					#--------------------------------------------------------------------------------------------------------------------------------------------------
					if Polar_size_ok:
						xx = x
						yy = y-1
						Plot = map.plot(xx,yy)
						if Plot.isFlatlands() or Plot.isWater():
							Polar_size += 1
							Polar_coords[(Polar_size * 2) - 2]=xx
							Polar_coords[(Polar_size * 2) - 1]=yy
							xx = x
							yy = y-2
							Plot = map.plot(xx,yy)
							if Plot.isFlatlands() or Plot.isWater():
								Polar_size_ok = False
							else:
								xx = x-1
								yy = y-1
								Corner4_Checked=True
								Plot = map.plot(xx,yy)
								if Plot.isFlatlands() or Plot.isWater():
									Polar_size += 1
									Polar_coords[(Polar_size * 2) - 2]=xx
									Polar_coords[(Polar_size * 2) - 1]=yy
									xx = x-2
									yy = y-1
									Plot = map.plot(xx,yy)
									if Plot.isFlatlands() or Plot.isWater():
										Polar_size_ok = False
									else:
										xx = x-1
										yy = y-2
										Plot = map.plot(xx,yy)
										if Plot.isFlatlands() or Plot.isWater():
											Polar_size_ok = False
								if not Corner3_Checked:			
									xx = x+1
									yy = y-1
									Plot = map.plot(xx,yy)
									if Plot.isFlatlands() or Plot.isWater():
										Polar_size += 1
										Polar_coords[(Polar_size * 2) - 2]=xx
										Polar_coords[(Polar_size * 2) - 1]=yy
										xx = x+2
										yy = y-1
										Plot = map.plot(xx,yy)
										if Plot.isFlatlands() or Plot.isWater():
											Polar_size_ok = False
										else:
											xx = x+1
											yy = y-2
											Plot = map.plot(xx,yy)
											if Plot.isFlatlands() or Plot.isWater():
												Polar_size_ok = False
					#--------------------------------------------------------------------------------------------------------------------------------------------------
					if Polar_size_ok:
						xx = x-1
						yy = y
						Plot = map.plot(xx,yy)
						if Plot.isFlatlands() or Plot.isWater():
							Polar_size += 1
							Polar_coords[(Polar_size * 2) - 2]=xx
							Polar_coords[(Polar_size * 2) - 1]=yy
							xx = x-2
							yy = y
							Plot = map.plot(xx,yy)
							if Plot.isFlatlands() or Plot.isWater():
								Polar_size_ok = False
							else:
								if not Corner4_Checked:
									xx = x-1
									yy = y-1
									Plot = map.plot(xx,yy)
									if Plot.isFlatlands() or Plot.isWater():
										Polar_size += 1
										Polar_coords[(Polar_size * 2) - 2]=xx
										Polar_coords[(Polar_size * 2) - 1]=yy
										xx = x-2
										yy = y-1
										Plot = map.plot(xx,yy)
										if Plot.isFlatlands() or Plot.isWater():
											Polar_size_ok = False
										else:
											xx = x-1
											yy = y-2
											Plot = map.plot(xx,yy)
											if Plot.isFlatlands() or Plot.isWater():
												Polar_size_ok = False
								if not Corner1_Checked:
									xx = x-1
									yy = y+1
									Plot = map.plot(xx,yy)
									if Plot.isFlatlands() or Plot.isWater():
										Polar_size += 1
										Polar_coords[(Polar_size * 2) - 2]=xx
										Polar_coords[(Polar_size * 2) - 1]=yy
										xx = x-2
										yy = y+1
										Plot = map.plot(xx,yy)
										if Plot.isFlatlands() or Plot.isWater():
											Polar_size_ok = False
										else:
											xx = x-1
											yy = y+2
											Plot = map.plot(xx,yy)
											if Plot.isFlatlands() or Plot.isWater():
												Polar_size_ok = False
				if Polar_size > 4:
					Polar_size_ok = False
				if Polar_size_ok:
					for coord in range(Polar_size):
						Plot = map.plot(Polar_coords[coord * 2],Polar_coords[(coord * 2) + 1])
						Plot.setTerrainType(Polar, 0, 0)

	#ensure at least two polar terrain is placed on map to prevent no food bug
	iPolarX = dice.get(iW,"polar location")
	Plot = map.plot(iPolarX,0)
	Plot.setTerrainType(Polar, 0, 0)
	Plot.setPlotType(PlotTypes.PLOT_LAND, 0, 0)
	Plot = map.plot(iPolarX-1,0)
	Plot.setTerrainType(Terrae, 0, 0)
	Plot.setPlotType(PlotTypes.PLOT_HILLS, 0, 0)
	Plot = map.plot(iPolarX+1,0)
	Plot.setTerrainType(Terrae, 0, 0)
	Plot.setPlotType(PlotTypes.PLOT_HILLS, 0, 0)
	Plot = map.plot(iPolarX,1)
	Plot.setTerrainType(Terrae, 0, 0)
	Plot.setPlotType(PlotTypes.PLOT_HILLS, 0, 0)
	
	iPolarX = dice.get(iW,"polar location")
	Plot = map.plot(iPolarX,iH - 1)
	Plot.setTerrainType(Polar, 0, 0)
	Plot.setPlotType(PlotTypes.PLOT_LAND, 0, 0)
	Plot = map.plot(iPolarX-1,iH - 1)
	Plot.setTerrainType(Terrae, 0, 0)
	Plot.setPlotType(PlotTypes.PLOT_HILLS, 0, 0)
	Plot = map.plot(iPolarX+1,iH - 1)
	Plot.setTerrainType(Terrae, 0, 0)
	Plot.setPlotType(PlotTypes.PLOT_HILLS, 0, 0)
	Plot = map.plot(iPolarX,iH - 2)
	Plot.setTerrainType(Terrae, 0, 0)
	Plot.setPlotType(PlotTypes.PLOT_HILLS, 0, 0)

def add_Terrae():
	gc = CyGlobalContext()
	map = gc.getMap()
	iW = map.getGridWidth()
	iH = map.getGridHeight()
	Terrae = gc.getInfoTypeForString("TERRAIN_TERRAE")
	for x in range(iW):
		for y in range(iH):
			Plot = CyMap().plot(x,y)
			if Plot.isHills():
				Plot.setTerrainType(Terrae, 0, 0)
	
def add_DustSeas():
	gc = CyGlobalContext()
	map = gc.getMap()
	dice = gc.getGame().getMapRand()
	iW = map.getGridWidth()
	iH = map.getGridHeight()
	terrainFrac = CyFractal()
	dustseasFrac = CyFractal()
	
	userInputDustSeas = map.getCustomMapOption(5)
	
	# Dust Sea density
	dustsea_list = [0, 5, 10, 15]
	dustsea_grains = [0, 4, 3, 2]
	dustseas = dustsea_list[userInputDustSeas]
	dustsea_grain = dustsea_grains[userInputDustSeas]

	dustseasFrac.fracInit(iW, iH, dustsea_grain, dice, 0, -1, -1)

	idustseasThreshold = dustseasFrac.getHeightFromPercent(dustseas)

	for x in range(iW):
		for y in range(iH):
			i = y*iW + x
			dustseaVal = dustseasFrac.getHeight(x,y)
			if dustseaVal <= idustseasThreshold:
				Plot = CyMap().plot(x,y)
				Plot.setTerrainType(gc.getInfoTypeForString("TERRAIN_DUSTSEA"), 0, 0)
				Plot.setPlotType(PlotTypes.PLOT_LAND, 0, 0)
	
def add_crater_rims():
	gc = CyGlobalContext()
	dice = gc.getGame().getMapRand()
	map = gc.getMap()
	iW = map.getGridWidth()
	iH = map.getGridHeight()
	MapArea = iW * iH
	CraterRim = gc.getInfoTypeForString("TERRAIN_CRATERRIM")
	CraterRimFeature = gc.getInfoTypeForString("FEATURE_JUNGLE") #Crater Rim (FEATURE_ICE is hardcoded)
	Ejecta = gc.getInfoTypeForString("FEATURE_FOREST") #Ejecta (FEATURE_FOREST is hardcoded)
	Dustsea = gc.getInfoTypeForString("TERRAIN_DUSTSEA")
	
	userInputCraterRim = map.getCustomMapOption(6)
	
	# Crater Rim density
	CraterRimMin_list = [15, 30, 50]
	CraterRimMax_list = [30, 35, 40]
	
	CraterRimMin = CraterRimMin_list[userInputCraterRim]
	CraterRimMax = CraterRimMax_list[userInputCraterRim]
	
	NumOfCraters = CraterRimMin*MapArea/1000 + MapArea * dice.get(CraterRimMax, "number of craters") / 1000

	for i in range (NumOfCraters):
		Rollx = dice.get((iW - 2), "Location of crater") + 1
		Rolly = dice.get((iH - 6), "Location of crater") + 3
		
		NumOfEjecta = dice.get(2, "number of Ejecta")

		m11Plot = map.plot((Rollx - 1),(Rolly - 1))
		m12Plot = map.plot((Rollx - 1),Rolly)
		m21Plot = map.plot(Rollx,(Rolly - 1))
		m22Plot = map.plot(Rollx,Rolly)
		m01Plot = map.plot((Rollx - 2),(Rolly - 1))
		m02Plot = map.plot((Rollx - 2),Rolly)
		m31Plot = map.plot((Rollx + 1),(Rolly - 1))
		m32Plot = map.plot((Rollx + 1),Rolly)
		m10Plot = map.plot((Rollx - 1),(Rolly - 2))
		m13Plot = map.plot((Rollx - 1),(Rolly + 1))
		m20Plot = map.plot(Rollx,(Rolly - 2))
		m23Plot = map.plot(Rollx,(Rolly + 1))
           
		m11tPlot = m11Plot.getTerrainType()
		m12tPlot = m12Plot.getTerrainType()
		m21tPlot = m21Plot.getTerrainType()
		m22tPlot = m22Plot.getTerrainType()
		m01tPlot = m01Plot.getTerrainType()
		m02tPlot = m02Plot.getTerrainType()
		m31tPlot = m31Plot.getTerrainType()
		m32tPlot = m31Plot.getTerrainType()
		m10tPlot = m01Plot.getTerrainType()
		m13tPlot = m13Plot.getTerrainType()
		m20tPlot = m20Plot.getTerrainType()
		m23tPlot = m23Plot.getTerrainType()

		if (not m13Plot.isWater()) and (not m23Plot.isWater()) and (not m10Plot.isWater()) and (not m20Plot.isWater()) and (not m31Plot.isWater()) and (not m32Plot.isWater()) and (not m01Plot.isWater()) and (not m02Plot.isWater()) and (m13tPlot != CraterRim) and (m23tPlot != CraterRim) and (m10tPlot != CraterRim) and (m20tPlot != CraterRim) and (m31tPlot != CraterRim) and (m32tPlot != CraterRim) and (m01tPlot != CraterRim) and (m02tPlot != CraterRim) and (m11tPlot != CraterRim) and (m12tPlot != CraterRim) and (m21tPlot != CraterRim) and (m22tPlot != CraterRim) and (not m11Plot.isPeak()) and (not m12Plot.isPeak()) and (not m21Plot.isPeak()) and (not m22Plot.isPeak()):
			m11Plot.setTerrainType(CraterRim, 0, 0)
			m21Plot.setTerrainType(CraterRim, 0, 0)
			m12Plot.setTerrainType(CraterRim, 0, 0)
			m22Plot.setTerrainType(CraterRim, 0, 0)
			m11Plot.setPlotType(PlotTypes.PLOT_LAND, 0, 0)
			m21Plot.setPlotType(PlotTypes.PLOT_LAND, 0, 0)
			m12Plot.setPlotType(PlotTypes.PLOT_LAND, 0, 0)
			m22Plot.setPlotType(PlotTypes.PLOT_LAND, 0, 0)
			m11Plot.setFeatureType(CraterRimFeature, -1)
			m21Plot.setFeatureType(CraterRimFeature, -1)
			m12Plot.setFeatureType(CraterRimFeature, -1)
			m22Plot.setFeatureType(CraterRimFeature, -1)
			for i in range (NumOfEjecta):
				EjectaX = dice.get(4, "Ejecta x location")
				EjectaY = dice.get(2, "Ejecta y location")
				xx = Rollx - 2 + EjectaX
				if EjectaX == 0 or EjectaX == 3:
					if EjectaY == 0:
						yy = Rolly - 1
					else:
						yy = Rolly
				if EjectaX == 1 or EjectaX == 2:
					if EjectaY == 0:
						yy = Rolly - 2
					else:
						yy = Rolly + 1
				Plot = map.plot(xx,yy)
				if not Plot.isPeak() and Plot.getTerrainType() != CraterRim and Plot.getTerrainType() != Dustsea:
					Plot.setFeatureType(Ejecta, -1)
			
def add_Rilles():
	gc = CyGlobalContext()
	dice = gc.getGame().getMapRand()
	map = gc.getMap()
	iW = map.getGridWidth()
	iH = map.getGridHeight()
	MapArea = iW * iH
	Rille = gc.getInfoTypeForString("TERRAIN_RILLE")
	
	userInputRille = map.getCustomMapOption(3)
	
	# Rille density
	RilleMin_list = [5, 10, 15]
	RilleMax_list = [10, 11, 12]
	
	RilleMin = RilleMin_list[userInputRille]
	RilleMax = RilleMax_list[userInputRille]
	
	NumOfRilles = RilleMin * MapArea / 1000 + MapArea * dice.get(RilleMax, "number of rilles") / 1000
	for i in range (NumOfRilles):
		iDirection = dice.get(4, "rille direction")
		iLength = dice.get(10, "rille length") + 3
		Rollx = dice.get((iW - 2), "Location of rille") + 1
		Rolly = dice.get((iH - 5), "Location of rille") + 2
		xx = Rollx
		yy = Rolly
		Plot = map.plot(xx,yy)
		PlotT = Plot.getTerrainType()
		Plot2 = map.plot(xx - 1,yy)
		Plot2T = Plot2.getTerrainType()
		Plot3 = map.plot(xx + 1,yy)
		Plot3T = Plot3.getTerrainType()
		Plot4 = map.plot(xx,yy - 1)
		Plot4T = Plot4.getTerrainType()
		Plot5 = map.plot(xx,yy + 1)
		Plot5T = Plot5.getTerrainType()
		if PlotT != Rille and Plot2T != Rille and Plot3T != Rille and Plot4T != Rille and Plot5T != Rille:
			Plot.setTerrainType(Rille, 0, 0)
			Plot.setPlotType(PlotTypes.PLOT_OCEAN, 0, 0)
			iPreviousDirection = iDirection
			for i2 in range (iLength):
			#------------------------------------------------------------------
				Diriction1Probability = 0
				yy = yy + 1
				Plot = map.plot(xx,yy)
				PlotT = Plot.getTerrainType()
				Plot2 = map.plot(xx - 1,yy)
				Plot2T = Plot2.getTerrainType()
				Plot3 = map.plot(xx + 1,yy)
				Plot3T = Plot3.getTerrainType()
				Plot4 = map.plot(xx,yy + 1)
				Plot4T = Plot4.getTerrainType()
				if PlotT != Rille and Plot2T != Rille and Plot3T != Rille and Plot4T != Rille:
					if iPreviousDirection != 3:
						if iDirection == 1:
							Diriction1Probability = 50
						elif iDirection == 2:
							Diriction1Probability = 25
						elif iDirection == 4:
							Diriction1Probability = 25
						else:
							Diriction1Probability = 2
				yy = yy - 1
			#------------------------------------------------------------------
				Diriction2Probability = 0
				xx = xx + 1
				Plot = map.plot(xx,yy)
				PlotT = Plot.getTerrainType()
				Plot2 = map.plot(xx,yy - 1)
				Plot2T = Plot2.getTerrainType()
				Plot3 = map.plot(xx,yy + 1)
				Plot3T = Plot3.getTerrainType()
				Plot4 = map.plot(xx + 1,yy)
				Plot4T = Plot4.getTerrainType()
				if PlotT != Rille and Plot2T != Rille and Plot3T != Rille and Plot4T != Rille:
					if iPreviousDirection != 4:
						if iDirection == 2:
							Diriction2Probability = 50
						elif iDirection == 1:
							Diriction2Probability = 25
						elif iDirection == 3:
							Diriction2Probability = 25
						else:
							Diriction2Probability = 2
				xx = xx - 1
			#------------------------------------------------------------------
				Diriction3Probability = 0
				yy = yy - 1
				Plot = map.plot(xx,yy)
				PlotT = Plot.getTerrainType()
				Plot2 = map.plot(xx - 1,yy)
				Plot2T = Plot2.getTerrainType()
				Plot3 = map.plot(xx + 1,yy)
				Plot3T = Plot3.getTerrainType()
				Plot4 = map.plot(xx,yy - 1)
				Plot4T = Plot4.getTerrainType()
				if PlotT != Rille and Plot2T != Rille and Plot3T != Rille and Plot4T != Rille:
					if iPreviousDirection != 1:
						if iDirection == 3:
							Diriction3Probability = 50
						elif iDirection == 2:
							Diriction3Probability = 25
						elif iDirection == 4:
							Diriction3Probability = 25
						else:
							Diriction3Probability = 2
				yy = yy + 1
			#------------------------------------------------------------------
				Diriction4Probability = 0
				xx = xx - 1
				Plot = map.plot(xx,yy)
				PlotT = Plot.getTerrainType()
				Plot2 = map.plot(xx,yy - 1)
				Plot2T = Plot2.getTerrainType()
				Plot3 = map.plot(xx,yy + 1)
				Plot3T = Plot3.getTerrainType()
				Plot4 = map.plot(xx - 1,yy)
				Plot4T = Plot4.getTerrainType()
				if PlotT != Rille and Plot2T != Rille and Plot3T != Rille and Plot4T != Rille:
					if iPreviousDirection != 2:
						if iDirection == 4:
							Diriction4Probability = 50
						elif iDirection == 1:
							Diriction4Probability = 25
						elif iDirection == 3:
							Diriction4Probability = 25
						else:
							Diriction4Probability = 2
				xx = xx + 1
			#------------------------------------------------------------------
				p = Diriction1Probability + Diriction2Probability + Diriction3Probability + Diriction4Probability
				if p == 0:
					break #end rille as it has run into a dead end
				RollDirection = dice.get(p, "rille plot direction")
				if RollDirection < Diriction1Probability:
					yy = yy + 1
					Plot = map.plot(xx,yy)
					if yy > iH - 2 or yy < 1:
						break #pevent rilles from going on the edge of the map as the graphics for these tiles will be messed up
					Plot.setTerrainType(Rille, 0, 0)
					Plot.setPlotType(PlotTypes.PLOT_OCEAN, 0, 0)
					iPreviousDirection = 1
				elif RollDirection < Diriction1Probability + Diriction2Probability:
					xx = xx + 1
					Plot = map.plot(xx,yy)
					if yy > iH - 2 or yy < 1:
						break #pevent rilles from going on the edge of the map as the graphics for these tiles will be messed up
					Plot.setTerrainType(Rille, 0, 0)
					Plot.setPlotType(PlotTypes.PLOT_OCEAN, 0, 0)
					iPreviousDirection = 2
				elif RollDirection < Diriction1Probability + Diriction2Probability + Diriction3Probability:
					yy = yy - 1
					Plot = map.plot(xx,yy)
					if yy > iH - 2 or yy < 1:
						break #pevent rilles from going on the edge of the map as the graphics for these tiles will be messed up
					Plot.setTerrainType(Rille, 0, 0)
					Plot.setPlotType(PlotTypes.PLOT_OCEAN, 0, 0)
					iPreviousDirection = 3
				elif RollDirection < Diriction1Probability + Diriction2Probability + Diriction3Probability + Diriction4Probability:
					xx = xx - 1
					Plot = map.plot(xx,yy)
					if yy > iH - 2 or yy < 1:
						break #pevent rilles from going on the edge of the map as the graphics for these tiles will be messed up
					Plot.setTerrainType(Rille, 0, 0)
					Plot.setPlotType(PlotTypes.PLOT_OCEAN, 0, 0)
					iPreviousDirection = 4

def addRivers():
#make sure no rivers are added
	gc = CyGlobalContext()
	map = CyMap()
	add_Rilles()
	if map.getCustomMapOption(5) != 0:
		add_DustSeas()
	add_crater_rims()
	add_Terrae()
	add_Polar()
	
def addLakes():
	return None
	
class MoonFeatureGenerator(CvMapGeneratorUtil.FeatureGenerator):
	def __init__(self, iCraterPercent=50, iCratersPercent=30,
                     Crater_grain=5, Craters_grain=5, fracXExp=-1, fracYExp=-1):
		self.gc = CyGlobalContext()
		self.map = CyMap()
		self.mapRand = self.gc.getGame().getMapRand()
		self.Crater = CyFractal()
		self.Craters = CyFractal()
		self.iFlags = 0
		self.iGridW = self.map.getGridWidth()
		self.iGridH = self.map.getGridHeight()
		
		self.iCraterPercent = iCraterPercent
		self.iCratersPercent = iCratersPercent
		
		self.Crater_grain = Crater_grain
		self.Craters_grain = Craters_grain

		self.fracXExp = fracXExp
		self.fracYExp = fracYExp
		
		self.__initFractals()
		self.__initFeatureTypes()
	
	def __initFractals(self):
		self.Crater.fracInit(self.iGridW+1, self.iGridH+1, self.Crater_grain, self.mapRand, self.iFlags, self.fracXExp, self.fracYExp)
		self.Craters.fracInit(self.iGridW+1, self.iGridH+1, self.Craters_grain, self.mapRand, self.iFlags, self.fracXExp, self.fracYExp)
		
		self.iCraterLevel = self.Crater.getHeightFromPercent(self.iCraterPercent)
		self.iCratersLevel = self.Craters.getHeightFromPercent(self.iCratersPercent)
		
	def __initFeatureTypes(self):
		self.featureCraters = self.gc.getInfoTypeForString("FEATURE_CRATERS")
		self.featureCrater = self.gc.getInfoTypeForString("FEATURE_CRATER")
		self.featureDome = self.gc.getInfoTypeForString("FEATURE_DOME")

	def addFeaturesAtPlot(self, iX, iY):
		"adds any appropriate features at the plot (iX, iY) where (0,0) is in the SW"
		pPlot = self.map.sPlot(iX, iY)
		Cratered = self.gc.getInfoTypeForString("TERRAIN_CRATERED")

		for iI in range(self.gc.getNumFeatureInfos()):
			if pPlot.canHaveFeature(iI):
				if self.mapRand.get(10000, "Add Feature PYTHON") < self.gc.getFeatureInfo(iI).getAppearanceProbability():
					pPlot.setFeatureType(iI, -1)

		if (pPlot.getFeatureType() == FeatureTypes.NO_FEATURE):
			self.addCraterAtPlot(pPlot, iX, iY)

		if (pPlot.getFeatureType() == FeatureTypes.NO_FEATURE):
			self.addCratersAtPlot(pPlot, iX, iY)

		if (pPlot.getFeatureType() == FeatureTypes.NO_FEATURE) and (pPlot.getTerrainType() == Cratered) and pPlot.isFlatlands():
			pPlot.setFeatureType(self.featureCraters, -1)

	def addCraterAtPlot(self, pPlot, iX, iY):
		if pPlot.canHaveFeature(self.featureCrater):
			if self.Crater.getHeight(iX+1, iY+1) <= self.iCraterLevel:
				pPlot.setFeatureType(self.featureCrater, -1)
	
	def addCratersAtPlot(self, pPlot, iX, iY):
		if pPlot.canHaveFeature(self.featureCraters):
			if self.Craters.getHeight(iX+1, iY+1) <= self.iCratersLevel:
				pPlot.setFeatureType(self.featureCraters, -1)

def addFeatures():
	global featuregen
	NiTextOut("Adding Features (Python Moon Map) ...")
	featuregen = MoonFeatureGenerator()
	featuregen.addFeatures()
	return 0
	
def add_He3():
#add He3 resources near player
    gc = CyGlobalContext()
    CraterRim = gc.getInfoTypeForString("TERRAIN_CRATERRIM")
    DustSea = gc.getInfoTypeForString("TERRAIN_DUSTSEA")
    He3 = gc.getInfoTypeForString("BONUS_HELIUM3")
    for iI in range(gc.getMAX_CIV_PLAYERS()):
	if (gc.getPlayer(iI).isAlive()):
            iStartX = gc.getPlayer(iI).getStartingPlot().getX()
            iStartY = gc.getPlayer(iI).getStartingPlot().getY()
            dice = gc.getGame().getMapRand()
            NumOfHe3 = 1 + dice.get(1, "number of Helium 3")
            x = 0
            loop = 0
            while (x < 1) and (loop < 100):
                loop = loop + 1
                xloc = iStartX + dice.get(5, "x location") - 2
                yloc = iStartY + dice.get(5, "y location") - 2
                mPlot = CyMap().plot(xloc,yloc)
                mtPlot = mPlot.getTerrainType()
                if (mtPlot != CraterRim) and (mtPlot != DustSea) and (not mPlot.isPeak()):
                    mPlot.setBonusType(He3)
                    x = x + 1
            while (x < NumOfHe3) and (loop < 100):
                loop = loop + 1
                xloc = iStartX + dice.get(7, "x location") - 3
                yloc = iStartY + dice.get(7, "y location") - 3
                mPlot = CyMap().plot(xloc,yloc)
                mtPlot = mPlot.getTerrainType()
                if (mtPlot != CraterRim) and (mtPlot != DustSea) and (not mPlot.isPeak()):
                    mPlot.setBonusType(He3)
                    x = x + 1

def normalizeAddRiver():
	return None

def normalizeRemovePeaks():
	return None

def normalizeAddLakes():
	return None

def normalizeRemoveBadFeatures():
	return None

def normalizeRemoveBadTerrain():
	return None

def normalizeAddFoodBonuses():
	return None

def normalizeAddGoodTerrain():
	return None

def normalizeAddExtras():
	return None

def startHumansOnSameTile():
	add_He3()

	"Returns true if all human units should start on the same tile"
	return True